//package com.ndbg.demo.shiro;
//
//
//import com.alibaba.fastjson.JSONObject;
//import com.ndbg.demo.shiro.utils.JwtUtil;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
//
//import javax.servlet.ServletRequest;
//import javax.servlet.ServletResponse;
//import javax.servlet.http.Cookie;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//
///**
// * @author chenXB
// * @createTime 2023年09月23日 09:37:00
// */
//@Slf4j
//public class JwtFilter extends BasicHttpAuthenticationFilter {
//    public static final String ACCESS_TOKEN = "accessToken";
//    public static final String AJAX_SIGN = "XMLHttpRequest";
//
//    /**
//     * 检测header里面是否包含Authorization字段 或 检测cookie里是否包含accessToken
//     * 判断用户是否尝试登入
//     */
//    @Override
//    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
//        HttpServletRequest req = (HttpServletRequest) request;
//        if (StringUtils.isNotEmpty(req.getHeader(JwtUtil.TOKEN))) {
//            return true;
//        }
//        return StringUtils.isNotEmpty(this.getTokenWithCookie(req));
//    }
//
//    @Override
//    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) {
//        log.warn("isAccessAllowed 方法被调用");
//        //这里先让它始终返回false来使用onAccessDenied()方法
//        return false;
//    }
//
//    @Override
//    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
//        log.warn("onAccessDenied 方法被调用");
//        //这个地方和前端约定，要求前端将jwtToken放在请求的Header部分
//
//        //所以以后发起请求的时候就需要在Header中放一个Authorization，值就是对应的Token
//        HttpServletRequest request = (HttpServletRequest) servletRequest;
//        String jwt = request.getHeader("Authorization");
//        log.info("请求的 Header 中藏有 jwtToken {}", jwt);
//        JwtToken jwtToken = new JwtToken(jwt);
//        /*
//         * 下面就是固定写法
//         * */
//        try {
//            // 委托 realm 进行登录认证
//            //所以这个地方最终还是调用JwtRealm进行的认证
//            getSubject(servletRequest, servletResponse).login(jwtToken);
//            //也就是subject.login(token)
//        } catch (Exception e) {
//            e.printStackTrace();
//            onLoginFail(servletResponse);
//            //调用下面的方法向客户端返回错误信息
//            return false;
//        }
//        return true;
//    }
//
//    //登录失败时默认返回 401 状态码
//    private void onLoginFail(ServletResponse response) throws IOException {
////        HttpServletResponse httpResponse = (HttpServletResponse) response;
////        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
////        httpResponse.getWriter().write("login error");
//        HttpServletResponse httpResponse = (HttpServletResponse) response;
//        httpResponse.setContentType("application/json;charset=utf-8");
//        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
////        httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
//        httpResponse.setCharacterEncoding("UTF-8");
//        JSONObject jsonObject = new JSONObject();
//        //处理登录失败的异常
//        jsonObject.put("status", 403);
//        jsonObject.put("msg", "登录凭证已失效，请重新登录");
//        try {
//            httpResponse.getWriter().print(jsonObject.toString());
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
//    }
//
//    /**
//     * 对跨域提供支持
//     */
//    @Override
//    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
//        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
//        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
//        httpServletResponse.setHeader("Access-Control-Allow-Headers",
//                httpServletRequest.getHeader("Access-Control-Request-Headers"));
//        // 跨域时会首先发送一个OPTIONS请求，这里我们给OPTIONS请求直接返回正常状态
////        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
////            httpServletResponse.setStatus(HttpStatus.OK.value());
////            return false;
////        }
//        return super.preHandle(request, response);
//    }
//
//
////    /**
////     * 刷新AccessToken，进行判断RefreshToken是否过期，未过期就返回新的AccessToken且继续正常访问
////     */
////    private boolean refreshToken(ServletRequest request, ServletResponse response) {
////        // 获取Token(Shiro中getAuthzHeader方法已经实现)
////        String token = this.getAuthzHeader(request);
////        // 获取当前Token的帐号信息
////        String username = JwtUtil.getClaim(token, SecurityConsts.USERNAME);
////        String refreshTokenCacheKey = SecurityConsts.REFRESH_TOKEN + username;
////        // 判断Redis中RefreshToken是否存在
////        if (jwtRedisCache.get(refreshTokenCacheKey) != null) {
////            // 获取RefreshToken时间戳,及Token中的时间戳
////            // 相比如果一致，进行Token刷新
////            String currentTimeMillisRedis = (String) jwtRedisCache.get(refreshTokenCacheKey);
////            String tokenMillis = JwtUtil.getClaim(token, SecurityConsts.CURRENT_TIME_MILLIS);
////
////            if (tokenMillis.equals(currentTimeMillisRedis)) {
////
////                // 设置RefreshToken中的时间戳为当前最新时间戳,并重制ip缓存时间
////                String currentTimeMillis = String.valueOf(System.currentTimeMillis());
////                jwtRedisCache.put(refreshTokenCacheKey, currentTimeMillis, jwtConfig.getRefreshTokenExpireTime());
////                jwtRedisCache.put(SecurityConsts.IP_TOKEN+username, JwtUtil.getIpAddress((HttpServletRequest) request), jwtConfig.getRefreshTokenExpireTime());
////                // 刷新AccessToken，为当前最新时间戳
////                token = JwtUtil.sign(username, currentTimeMillis);
////
////                // 使用AccessToken 再次提交给ShiroRealm进行认证，如果没有抛出异常则登入成功，返回true
////                JwtToken jwtToken = new JwtToken(token);
////                this.getSubject(request, response).login(jwtToken);
////
////                // 设置响应的Header头新Token
////                HttpServletResponse httpServletResponse = (HttpServletResponse) response;
////                httpServletResponse.setHeader(SecurityConsts.REQUEST_AUTH_HEADER, token);
////                httpServletResponse.setHeader("Access-Control-Expose-Headers", SecurityConsts.REQUEST_AUTH_HEADER);
////                return true;
////            }
////        }
////        return false;
////    }
//
//
//    /**
//     * 获取Cookie里的token
//     *
//     * @param request
//     * @return
//     */
//    public String getTokenWithCookie(HttpServletRequest request) {
//        Cookie[] cookies = request.getCookies();
//        String token = null;
//        if (cookies != null && cookies.length > 0) {
//            for (Cookie cookie : cookies) {
//                if (ACCESS_TOKEN.equals(cookie.getName())) {
//                    token = cookie.getValue();
//                    break;
//                }
//            }
//        }
//        return token;
//    }
//
//
////    @Override
////    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
////        UserContext.remove();
////        AuditContext.remove();
////        super.afterCompletion(request, response, exception);
////    }
//}
